/*!
 * Noty Helpers Javascript From JQuery Javascript Library
 *
 * Ported by Maksim Pecherskiy.  Original Licensing:
 *
 * http://jquery.com/
 *
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 * Copyright 2011, The Dojo Foundation
 * Released under the MIT, BSD, and GPL Licenses.
 *
 * Date: Mon Nov 21 21:11:03 2011 -0500
 */


(function () {

    // String to Object flags format cache
    var flagsCache = {};

// Convert String-formatted flags into Object-formatted ones and store in cache
    function createFlags(flags) {
        var object = flagsCache[ flags ] = {},
                i, length;
        flags = flags.split(/\s+/);
        for (i = 0, length = flags.length; i < length; i++) {
            object[ flags[i] ] = true;
        }
        return object;
    }

    jQuery.extend({

        _mark: function (elem, type) {
            if (elem) {
                type = (type || "fx") + "mark";
                jQuery.data(elem, type, (jQuery.data(elem, type, undefined, true) || 0) + 1, true);
            }
        },

        _unmark: function (force, elem, type) {
            if (force !== true) {
                type = elem;
                elem = force;
                force = false;
            }
            if (elem) {
                type = type || "fx";
                var key = type + "mark",
                        count = force ? 0 : ((jQuery.data(elem, key, undefined, true) || 1) - 1);
                if (count) {
                    jQuery.data(elem, key, count, true);
                } else {
                    jQuery.removeData(elem, key, true);
                    handleQueueMarkDefer(elem, type, "mark");
                }
            }
        },

        queue: function (elem, type, data) {
            if (elem) {
                type = (type || "fx") + "queue";
                var q = jQuery.data(elem, type, undefined, true);
                // Speed up dequeue by getting out quickly if this is just a lookup
                if (data) {
                    if (!q || jQuery.isArray(data)) {
                        q = jQuery.data(elem, type, jQuery.makeArray(data), true);
                    } else {
                        q.push(data);
                    }
                }
                return q || [];
            }
        },

        dequeue: function (elem, type) {
            type = type || "fx";

            var queue = jQuery.queue(elem, type),
                    fn = queue.shift(),
                    defer;

            // If the fx queue is dequeued, always remove the progress sentinel
            if (fn === "inprogress") {
                fn = queue.shift();
            }

            if (fn) {
                // Add a progress sentinel to prevent the fx queue from being
                // automatically dequeued
                if (type === "fx") {
                    queue.unshift("inprogress");
                }

                fn.call(elem, function () {
                    jQuery.dequeue(elem, type);
                });
            }

            if (!queue.length) {
                jQuery.removeData(elem, type + "queue", true);
                handleQueueMarkDefer(elem, type, "queue");
            }
        }
    });

    jQuery.fn.extend({
        queue: function (type, data) {
            if (typeof type !== "string") {
                data = type;
                type = "fx";
            }

            if (data === undefined) {
                return jQuery.queue(this[0], type);
            }
            return this.each(function () {
                var queue = jQuery.queue(this, type, data);

                if (type === "fx" && queue[0] !== "inprogress") {
                    jQuery.dequeue(this, type);
                }
            });
        },
        dequeue: function (type) {
            return this.each(function () {
                jQuery.dequeue(this, type);
            });
        },
        // Based off of the plugin by Clint Helfers, with permission.
        // http://blindsignals.com/index.php/2009/07/jquery-delay/
        delay: function (time, type) {
            time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
            type = type || "fx";

            return this.queue(type, function () {
                var elem = this;
                setTimeout(function () {
                    jQuery.dequeue(elem, type);
                }, time);
            });
        },
        clearQueue: function (type) {
            return this.queue(type || "fx", []);
        },
        // Get a promise resolved when queues of a certain type
        // are emptied (fx is the type by default)
        promise: function (type, object) {
            if (typeof type !== "string") {
                object = type;
                type = undefined;
            }
            type = type || "fx";
            var defer = jQuery.Deferred(),
                    elements = this,
                    i = elements.length,
                    count = 1,
                    deferDataKey = type + "defer",
                    queueDataKey = type + "queue",
                    markDataKey = type + "mark",
                    tmp;
            function resolve() {
                if (!(--count)) {
                    defer.resolveWith(elements, [elements]);
                }
            }
            while (i--) {
                if ((tmp = jQuery.data(elements[ i ], deferDataKey, undefined, true) ||
                        (jQuery.data(elements[ i ], queueDataKey, undefined, true) ||
                                jQuery.data(elements[ i ], markDataKey, undefined, true)) &&
                        jQuery.data(elements[ i ], deferDataKey, jQuery._Deferred(), true))) {
                    count++;
                    tmp.done(resolve);
                }
            }
            resolve();
            return defer.promise();
        }
    });

    function handleQueueMarkDefer(elem, type, src) {
        var deferDataKey = type + "defer",
                queueDataKey = type + "queue",
                markDataKey = type + "mark",
                defer = jQuery._data(elem, deferDataKey);
        if (defer &&
                (src === "queue" || !jQuery._data(elem, queueDataKey)) &&
                (src === "mark" || !jQuery._data(elem, markDataKey))) {
            // Give room for hard-coded callbacks to fire first
            // and eventually mark/queue something else on the element
            setTimeout(function () {
                if (!jQuery._data(elem, queueDataKey) &&
                        !jQuery._data(elem, markDataKey)) {
                    jQuery.removeData(elem, deferDataKey, true);
                    defer.fire();
                }
            }, 0);
        }
    }



    jQuery.Callbacks = function (flags) {

        // Convert flags from String-formatted to Object-formatted
        // (we check in cache first)
        flags = flags ? (/*flagsCache[ flags ] || */createFlags(flags)) : {};

        var // Actual callback list
                list = [],
                // Stack of fire calls for repeatable lists
                stack = [],
                // Last fire value (for non-forgettable lists)
                memory,
                // Flag to know if list is currently firing
                firing,
                // First callback to fire (used internally by add and fireWith)
                firingStart,
                // End of the loop when firing
                firingLength,
                // Index of currently firing callback (modified by remove if needed)
                firingIndex,
                // Add one or several callbacks to the list
                add = function (args) {
                    var i,
                            length,
                            elem,
                            type,
                            actual;
                    for (i = 0, length = args.length; i < length; i++) {
                        elem = args[ i ];
                        type = jQuery.type(elem);
                        if (type === "array") {
                            // Inspect recursively
                            add(elem);
                        } else if (type === "function") {
                            // Add if not in unique mode and callback is not in
                            if (!flags.unique || !self.has(elem)) {
                                list.push(elem);
                            }
                        }
                    }
                },
                // Fire callbacks
                fire = function (context, args) {
                    args = args || [];
                    memory = !flags.memory || [context, args];
                    firing = true;
                    firingIndex = firingStart || 0;
                    firingStart = 0;
                    firingLength = list.length;
                    for (; list && firingIndex < firingLength; firingIndex++) {
                        if (list[ firingIndex ].apply(context, args) === false && flags.stopOnFalse) {
                            memory = true; // Mark as halted
                            break;
                        }
                    }
                    firing = false;
                    if (list) {
                        if (!flags.once) {
                            if (stack && stack.length) {
                                memory = stack.shift();
                                self.fireWith(memory[ 0 ], memory[ 1 ]);
                            }
                        } else if (memory === true) {
                            self.disable();
                        } else {
                            list = [];
                        }
                    }
                },
                // Actual Callbacks object
                self = {
                    // Add a callback or a collection of callbacks to the list
                    add: function () {
                        if (list) {
                            var length = list.length;
                            add(arguments);
                            // Do we need to add the callbacks to the
                            // current firing batch?
                            if (firing) {
                                firingLength = list.length;
                                // With memory, if we're not firing then
                                // we should call right away, unless previous
                                // firing was halted (stopOnFalse)
                            } else if (memory && memory !== true) {
                                firingStart = length;
                                fire(memory[ 0 ], memory[ 1 ]);
                            }
                        }
                        return this;
                    },
                    // Remove a callback from the list
                    remove: function () {
                        if (list) {
                            var args = arguments,
                                    argIndex = 0,
                                    argLength = args.length;
                            for (; argIndex < argLength; argIndex++) {
                                for (var i = 0; i < list.length; i++) {
                                    if (args[ argIndex ] === list[ i ]) {
                                        // Handle firingIndex and firingLength
                                        if (firing) {
                                            if (i <= firingLength) {
                                                firingLength--;
                                                if (i <= firingIndex) {
                                                    firingIndex--;
                                                }
                                            }
                                        }
                                        // Remove the element
                                        list.splice(i--, 1);
                                        // If we have some unicity property then
                                        // we only need to do this once
                                        if (flags.unique) {
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        return this;
                    },
                    // Control if a given callback is in the list
                    has: function (fn) {
                        if (list) {
                            var i = 0,
                                    length = list.length;
                            for (; i < length; i++) {
                                if (fn === list[ i ]) {
                                    return true;
                                }
                            }
                        }
                        return false;
                    },
                    // Remove all callbacks from the list
                    empty: function () {
                        list = [];
                        return this;
                    },
                    // Have the list do nothing anymore
                    disable: function () {
                        list = stack = memory = undefined;
                        return this;
                    },
                    // Is it disabled?
                    disabled: function () {
                        return !list;
                    },
                    // Lock the list in its current state
                    lock: function () {
                        stack = undefined;
                        if (!memory || memory === true) {
                            self.disable();
                        }
                        return this;
                    },
                    // Is it locked?
                    locked: function () {
                        return !stack;
                    },
                    // Call all callbacks with the given context and arguments
                    fireWith: function (context, args) {
                        if (stack) {
                            if (firing) {
                                if (!flags.once) {
                                    stack.push([context, args]);
                                }
                            } else if (!(flags.once && memory)) {
                                fire(context, args);
                            }
                        }
                        return this;
                    },
                    // Call all the callbacks with the given arguments
                    fire: function () {
                        self.fireWith(this, arguments);
                        return this;
                    },
                    // To know if the callbacks have already been called at least once
                    fired: function () {
                        return !!memory;
                    }
                };

        return self;
    };



    jQuery.fn.extend({
        // Get a promise resolved when queues of a certain type
        // are emptied (fx is the type by default)
        promise: function (type, object) {
            if (typeof type !== "string") {
                object = type;
                type = undefined;
            }
            type = type || "fx";
            var defer = jQuery.Deferred(),
                    elements = this,
                    i = elements.length,
                    count = 1,
                    deferDataKey = type + "defer",
                    queueDataKey = type + "queue",
                    markDataKey = type + "mark",
                    tmp;
            function resolve() {
                if (!(--count)) {
                    defer.resolveWith(elements, [elements]);
                }
            }
            while (i--) {
                if ((tmp = jQuery.data(elements[ i ], deferDataKey, undefined, true) ||
                        (jQuery.data(elements[ i ], queueDataKey, undefined, true) ||
                                jQuery.data(elements[ i ], markDataKey, undefined, true)) &&
                        jQuery.data(elements[ i ], deferDataKey, jQuery.Callbacks("once memory"), true))) {
                    count++;
                    tmp.add(resolve);
                }
            }
            resolve();
            return defer.promise();
        }
    });
})();